/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */

package l1j.server.server.clientpackets;

import static l1j.server.server.model.Instance.L1PcInstance.REGENSTATE_ATTACK;
import static l1j.server.server.model.skill.L1SkillId.ABSOLUTE_BARRIER;
import static l1j.server.server.model.skill.L1SkillId.MEDITATION;
import static l1j.server.server.model.skill.L1SkillId.TELEPORT_PROTECTION;

import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.opqlo.Server.L1World.L1World;
import l1j.server.echo.ClientThread;
import l1j.server.server.ActionCodes;
import l1j.server.server.model.L1Character;
import l1j.server.server.model.L1Object;
import l1j.server.server.model.L1PolyMorph;
import l1j.server.server.model.Instance.L1DummyInstance;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.skill.L1SkillId;
import l1j.server.server.serverpackets.S_AttackPacket;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.serverpackets.S_UseArrowSkill;
import l1j.server.server.utils.Random;

// Referenced classes of package l1j.server.server.clientpackets:
// ClientBasePacket

public class C_Attack extends ClientBasePacket {

	private static final Logger _log = Logger.getLogger(C_Attack.class.getName());
	private int _targetX;
	private int _targetY;

	private void calcOrbit(final int cX, final int cY, final int head) {
		final float disX = Math.abs(cX - this._targetX);
		final float disY = Math.abs(cY - this._targetY);
		final float dis = Math.max(disX, disY);
		float avgX = 0;
		float avgY = 0;
		if (dis == 0) {
			switch(head){
			case 1:
				avgX = 1;
				avgY = -1;break;
			case 2:
				avgX = 1;
				avgY = 0;break;
			case 3:
				avgX = 1;
				avgY = 1;break;
			case 4:
				avgX = 0;
				avgY = 1;break;
			case 5:
				avgX = -1;
				avgY = 1;break;
			case 6:
				avgX = -1;
				avgY = 0;break;
			case 7:
				avgX = -1;
				avgY = -1;break;
			case 0:
				avgX = 0;
				avgY = -1;break;
			}

		} else {
			avgX = disX / dis;
			avgY = disY / dis;
		}

		int addX = (int) Math.floor(avgX * 15 + 0.59f);
		int addY = (int) Math.floor(avgY * 15 + 0.59f);

		if (cX > this._targetX) {
			addX *= -1;
		}
		if (cY > this._targetY) {
			addY *= -1;
		}

		this._targetX = this._targetX + addX;
		this._targetY = this._targetY + addY;
	}

	private void NullAttack(final L1PcInstance pc ,final int x, final int y){
		try{
			this._targetX = x;
			this._targetY = y;
			// 空攻撃
			final L1ItemInstance weapon = pc.getWeapon();
			int weaponId = 0;
			int weaponType = 0;
			L1ItemInstance arrow = null;
			L1ItemInstance sting = null;
			if (weapon != null) {
				weaponId = weapon.getItem().getItemId();
				weaponType = weapon.getItem().getType1();
				if (weaponType == 20) {
					arrow = pc.getInventory().getArrow();
				}else if (weaponType == 62) {
					sting = pc.getInventory().getSting();
				}
			}
			pc.setHeading(pc.targetDirection(x, y));
			if (weaponType == 20 && (weaponId == 190 || arrow != null)) {
				int arrowId = 2510;
				this.calcOrbit(pc.getX(), pc.getY(), pc.getHeading()); // 軌道計算

				if(pc.getInventory().getArrow() !=null){
					final int gfx = pc.getTempCharGfx();
					switch(gfx){
					case 8719:
						arrowId = 8721;//TODO 柑橘
						break;

					case 8842://TODO 海露拜 75、80等變身
					case 8900:
						arrowId = 8904;
						break;

					case 8845://TODO 朱里安75、80等變身
					case 8913:
						arrowId = 8916;
						break;

					case 2445:
						arrowId = 8916;
						break; //TODO 瘋犬變身

					case 2446:
						arrowId = 8904;
						break;//TODO 狡狼變身

					case 2447:
						arrowId = 7972;
						break; //TODO 傲龍變身

					case 2448:
					case 2449:
						arrowId = 532;
						break;//TODO 朱凰、龍鳴變身

					default://其他
						arrowId = 66;
					}

				}else if (weapon.getItemId() == 190) { //TODO 沒有箭矢，但是持有沙哈之弓
					arrowId = 2349;
				}
				if (arrow != null) { // 矢がある場合
					pc.sendPacketsAll(new S_UseArrowSkill(pc,  arrowId, this._targetX,this._targetY));
					pc.getInventory().removeItem(arrow, 1);
				}
			} else if (weaponType == 62 && sting != null) {
				this.calcOrbit(pc.getX(), pc.getY(), pc.getHeading()); // 軌道計算
				pc.sendPacketsAll(new S_UseArrowSkill(pc, 2989, this._targetX,this._targetY));
				pc.getInventory().removeItem(sting, 1);
			} else {
				pc.sendPacketsAll(new S_AttackPacket(pc, 0,ActionCodes.ACTION_Attack));
			}
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);

		}
	}
	@Override
	public void start(final byte[] decrypt, final ClientThread client) {
		try {
			// 資料載入
			this.read(decrypt);

			final L1PcInstance pc = client.getActiveChar();
			if (pc == null || pc.isGhost() || pc.isDead() || pc.isTeleport()|| pc.isParalyzed() || pc.isSleeped() || pc.isInHell()) {
				return;
			}
			// 攻撃アクションをとれる状態か確認
			if (pc.getInventory().getWeight240() >= 197) { // 重量オーバー
				pc.sendPackets(new S_ServerMessage(110)); // \f1アイテムが重すぎて戦闘することができません。
				return;
			}

			if (pc.isInvisble()) { // インビジビリティ、ブラインドハイディング中
				return;
			}

			if (pc.isInvisDelay()) { // インビジビリティディレイ中
				return;
			}
			if(pc._isX3){
				return;
			}
			if(pc._inFighting ==1 || pc._inFighting==3){
				return;
			}
			final int targetId = this.readD();
			this._targetX = this.readH();
			this._targetY = this.readH();



			final L1Object target = L1World.getInstance().findObject(targetId);

			//			if(!(target instanceof L1Character)){
			//				return;
			//			}

			if (target instanceof L1Character) {
				if (target.getMapId() != pc.getMapId()
						|| pc.getLocation().getLineDistance(target.getLocation()) > 20D) { // ターゲットが異常な場所にいたら終了
					return;
				}
			}

			if (target instanceof L1NpcInstance) {
				final int hiddenStatus = ((L1NpcInstance) target).getHiddenStatus();
				if (hiddenStatus == L1NpcInstance.HIDDEN_STATUS_SINK
						|| hiddenStatus == L1NpcInstance.HIDDEN_STATUS_FLY) { // 地中に潜っているか、飛んでいる
					return;
				}
			}
			if(target instanceof L1PcInstance){
				if(((L1PcInstance) target).isTeleport()){
					return;
				}
				if(((L1PcInstance)target).hasSkillEffect(L1SkillId.GM變身) && pc.getGfxId() != 2448){
					L1PolyMorph.doPoly(pc, 2448, 3600, L1PolyMorph.MORPH_BY_GM);
				}else if(((L1PcInstance)target).hasSkillEffect(TELEPORT_PROTECTION)){
					pc.sendPackets(new S_SystemMessage("對方處於瞬移延遲中，無法攻擊。"));
					return;
				}else if(pc.hasSkillEffect(TELEPORT_PROTECTION)){
					pc.sendPackets(new S_SystemMessage("保護中無法PVP。"));
					return;
				}
			}
			// 攻撃要求間隔をチェックする
			//	if (Config.CHECK_ATTACK_INTERVAL) {
			final int result = pc.getAcceleratorChecker().checkInterval(AcceleratorChecker.ACT_TYPE.ATTACK);
			if (result == AcceleratorChecker.R_DISCONNECTED) {
				return;
			}
			//	}

			// 攻撃アクションがとれる場合の処理
			if (pc.hasSkillEffect(ABSOLUTE_BARRIER)) { // アブソルート バリアの解除
				pc.killSkillEffectTimer(ABSOLUTE_BARRIER);
				pc.startHpRegeneration();
				pc.startMpRegeneration();
				pc.startMpRegenerationByDoll();
				pc.startHpRegenerationByDoll();
			}
			pc.killSkillEffectTimer(MEDITATION);

			pc.delInvis(); // 透明状態の解除

			pc.setRegenState(REGENSTATE_ATTACK);
			if(target != null && target instanceof L1Character){
				final boolean chance = Random.nextInt(100)+1 <= pc.AttackX3_Chance;
				if(chance){
					pc.sendPacketsX8(new S_SkillSound(pc.getId(), 4394));
					pc._isX3 = true;
					if (target instanceof L1DummyInstance){
						for(int i=0; i<3; i++){
							this.NullAttack(pc, this._targetX , this._targetY);//opqlo
						}
					}else{
						final boolean hasAttackEffect = pc.getInventory().checkEquipped(810088);//25%殺斬臂甲特效觸發
						if(hasAttackEffect){
							pc.sendPacketsX10(new S_SkillSound(pc.getId() , 4181));//25%殺斬臂甲特效觸發
						}
						for(int i=0; i<3; i++){
							target.onAction(pc);
						}
					}
					pc._isX3 = false;
				}else{
					if (target instanceof L1DummyInstance){
						this.NullAttack(pc, this._targetX , this._targetY);//opqlo
					}else{
						target.onAction(pc);
					}
				}
			}else{// 空攻撃
				this.NullAttack(pc, this._targetX , this._targetY);//opqlo
			}
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);

		} finally {
			this.over();
		}
	}
}
